package com.rtf.framework.es.config;

import com.netflix.hystrix.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Author: lichong
 * @Description: hystrix熔断器配置
 * @Date: 2021/7/5 14:02
 * @Version: 1.0
 */
@Component
public class AppEsHystrixConfig {
    private static final String GROUP_KEY_ES = "es";

    @Autowired
    private AppElasticSearchProperties properties;

    /**
     * 构建es请求的setter设置
     *
     *      metrics.rollingStats.timeInMilliseconds：该属性用来设置滚动时间窗的长度，单位为毫秒。该时间用于断路器判断健康度时需要收集信息的持续时间。断路器在收集指标信息时会根据设置的时间窗长度拆分成多个桶来累计各度量值，每个桶记录了一段时间的采集指标。例如，当为默认值10000毫秒时，断路器默认将其分成10个桶，每个桶记录1000毫秒内的指标信息。
     *      metrics.rollingStats.numBuckets：用来设置滚动时间窗统计指标信息时划分“桶”的数量。默认值为10。
     *      metrics.rollingPercentile.enabled：用来设置对命令执行延迟是否使用百分位数来跟踪和计算。默认为true，如果设置为false，那么所有的概要统计都将返回-1。
     *      metrics.rollingPercentile.timeInMilliseconds：用来设置百分位统计的滚动窗口的持续时间，单位为毫秒。
     *      metrics.rollingPercentile.numBuckets：用来设置百分位统计滚动窗口中使用桶的数量。
     *      metrics.rollingPercentile.bucketSize：用来设置每个“桶”中保留的最大执行数。
     *      metrics.healthSnapshot.intervalInMilliseconds：用来设置采集影响断路器状态的健康快照的间隔等待时间。
     *
     * @param commandName
     * @return
     */
    public HystrixCommand.Setter getESHystrixSetter(String commandName) {
        HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter()
                //默认为false，是否根据coreSize和maximumSize计算actualMaximumSize
                .withAllowMaximumSizeToDivergeFromCoreSize(true)
                //定义线程池的核心线程数量
                .withCoreSize(properties.getHystrix().getCoreSize())
                //定义线程池的最大线程数量
                .withMaximumSize(properties.getHystrix().getCoreSize())
                //超过这个时间多于coreSize数量的线程会被回收，只有maximumsize大于coreSize，这个值才有意义
                //.withKeepAliveTimeMinutes(umsHystrixProperties.getEs().getKeepAliveTimeMinutes())
                //定义线程池的大小
                .withMaxQueueSize(properties.getHystrix().getMaxQueueSize())
                //hystrix 定义线程池时一个手动设置的“最大”大小，即使未达到maxQueueSize ，也会发生拒绝。
                //         * 这样做是因为 BlockingQueue的 maxQueueSize不能动态更改，这里希望支持动态更改影响拒绝的队列大小
                .withQueueSizeRejectionThreshold(properties.getHystrix().getQueueSizeRejectionThreshold());

        /**
         * 开启fallback，启动超时设置
         */
        HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
                //定义是否
                .withFallbackEnabled(true)
                .withCircuitBreakerEnabled(true)
                //定义是否启用执行超时
                .withExecutionTimeoutEnabled(true)
                //设置熔断的执行策略，线程池或者信号量
                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
                //定义执行超时时长
                .withExecutionTimeoutInMilliseconds(properties.getHystrix().getExecutionTimeoutInMilliseconds())
                //熔断恢复时长，这里是默认5s
                .withCircuitBreakerSleepWindowInMilliseconds(properties.getHystrix().getCircuitBreakerSleepWindowInMilliseconds())
                //在一个rolling window内的所有请求里,发生问题的请求占所有请求的百分比阈值, 50%也是默认值
                .withCircuitBreakerErrorThresholdPercentage(properties.getHystrix().getCircuitBreakerErrorThresholdPercentage())
                //指定rolling window内请求的个数设定的阈值，如果大于该值则有可能出发熔断。 只有当百分比阈值和错误个数阈值都超过时才触发熔断。
                .withCircuitBreakerRequestVolumeThreshold(properties.getHystrix().getCircuitBreakerRequestVolumeThreshold());


        HystrixCommand.Setter hystrixCommandSetter = HystrixCommand.Setter
                //定义小组key
                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(GROUP_KEY_ES))
                .andCommandKey(HystrixCommandKey.Factory.asKey(commandName))
                .andCommandPropertiesDefaults(commandProperties)
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(GROUP_KEY_ES))
                .andThreadPoolPropertiesDefaults(threadPoolProperties);

        return hystrixCommandSetter;
    }
}
